import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpStatus,
} from '@nestjs/common';
import { getExceptionByStatusCode, sendExceptionResponse } from 'src/utils';
import {
  PrismaClientKnownRequestError,
  PrismaClientUnknownRequestError,
  PrismaClientValidationError,
  PrismaClientRustPanicError,
  PrismaClientInitializationError,
} from '@prisma/client/runtime/library';

/**
 * 捕获 Prisma 异常
 * 可根据不同的 Prisma 错误代码返回对应的 HTTP 状态码和错误信息
 */
@Catch(
  PrismaClientKnownRequestError,
  PrismaClientUnknownRequestError,
  PrismaClientValidationError,
  PrismaClientRustPanicError,
  PrismaClientInitializationError,
)
export class PrismaExceptionFilter implements ExceptionFilter {
  catch(
    exception:
      | PrismaClientKnownRequestError
      | PrismaClientUnknownRequestError
      | PrismaClientValidationError
      | PrismaClientRustPanicError
      | PrismaClientInitializationError,
    host: ArgumentsHost,
  ) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();

    let statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
    let errMessage = 'Database connection error or query failed';

    // 针对已知请求错误进行细化处理
    if (exception instanceof PrismaClientKnownRequestError) {
      // 常见的 Prisma 错误码参考：https://www.prisma.io/docs/reference/api-reference/error-reference
      switch (exception.code) {
        case 'P2002': // 唯一约束冲突
          statusCode = HttpStatus.CONFLICT;
          errMessage = `Unique constraint failed on field(s): ${(exception.meta?.target as string[])?.join(', ')}`;
          break;
        case 'P2003': // 外键约束失败
          statusCode = HttpStatus.BAD_REQUEST;
          errMessage = `Foreign key constraint failed on field: ${exception.meta?.field_name}`;
          break;
        case 'P2025': // 记录不存在
          statusCode = HttpStatus.NOT_FOUND;
          errMessage = 'Record not found';
          break;
        default:
          statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
          errMessage = `Prisma known request error: ${exception.message}`;
          break;
      }
    } else if (exception instanceof PrismaClientValidationError) {
      statusCode = HttpStatus.BAD_REQUEST;
      errMessage = `Prisma validation error: ${exception.message}`;
    } else if (exception instanceof PrismaClientInitializationError) {
      statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
      errMessage = `Prisma initialization error: ${exception.message}`;
    } else if (exception instanceof PrismaClientRustPanicError) {
      statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
      errMessage = `Prisma Rust panic error: ${exception.message}`;
    } else if (exception instanceof PrismaClientUnknownRequestError) {
      statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
      errMessage = `Prisma unknown request error: ${exception.message}`;
    }

    const errorName = getExceptionByStatusCode(statusCode).error;

    // 发送异常响应
    sendExceptionResponse({
      response,
      statusCode,
      errorName,
      message: errMessage,
      detail: exception, // 可以包含 meta 或其他错误细节
      exception: {},
    });

    // 需要时可添加日志
    // this.logger.error(errMessage, { context: 'PrismaError', url: request.url, method: request.method, statusCode });
  }
}
